import axios from 'axios';
import {ElMessageBox, ElNotification} from 'element-plus';
import {saveAs} from 'file-saver';
import config from "@/config";
import token from '@/utils/token';
import modal from "@/utils/modal";
import storage from "@/utils/storage";

axios.defaults.baseURL = '';

axios.defaults.timeout = config.API_TIMEOUT;

// HTTP REQUEST 拦截器
axios.interceptors.request.use(
    (conf) => {
        let userToken = token.getUserToken();
        if (userToken) {
            conf.headers[config.API_TOKEN_NAME] = config.API_TOKEN_PREFIX + userToken;
        }
        if (!config.API_IS_REQUEST_CACHE && conf.method === 'get') {
            conf.params = conf.params || {};
            conf.params['_'] = new Date().getTime();
        }
        Object.assign(conf.headers, config.API_HEADERS);
        return conf;
    },
    (error) => {
        return Promise.reject(error);
    }
);

// FIX 多个 API 同时 401 时疯狂弹窗 BUG
let MessageBox_401_show = false

// HTTP RESPONSE 拦截器
axios.interceptors.response.use(
    (response) => {
        return response;
    },
    (error) => {
        if (error.response) {
            if (error.response.status === 404) {
                ElNotification.error({
                    title: '请求错误',
                    message: "Status:404，正在请求不存在的服务器记录！"
                });
            } else if (error.response.status === 500) {
                ElNotification.error({
                    title: '请求错误',
                    message: error.response.data.message || "Status:500，服务器发生错误！"
                });
            } else if (error.response.status === 401) {
                if (!MessageBox_401_show) {
                    MessageBox_401_show = true
                    ElMessageBox.confirm('当前用户已被登出或无权限访问当前资源，请尝试重新登录后再操作。', '无权限访问', {
                        type: 'error',
                        closeOnClickModal: false,
                        center: true,
                        confirmButtonText: '重新登录',
                        beforeClose: (action, instance, done) => {
                            MessageBox_401_show = false;
                            done();
                        }
                    }).then(() => {
                        token.logout();
                    }).catch(() => {
                    })
                }
            } else {
                ElNotification.error({
                    title: '请求错误',
                    message: error.message || `Status:${error.response.status}，未知错误！`
                });
            }
        } else {
            ElNotification.error({
                title: '请求错误',
                message: "请求服务器无响应！"
            });
        }
        return Promise.reject(error.response);
    }
);

const blobValidate = (data) => {
    return data.type !== 'application/json';
}

const saveTo = (text, name, options) => {
    saveAs(text, name, options);
}

const request = {
    /**
     * POST 请求
     * @param url 接口地址
     * @param data 请求参数
     * @param config 请求配置
     * @returns {Promise<unknown>} 结果
     */
    post: (url, data = {}, config = {}) => {
        return new Promise((resolve, reject) => {
            axios({method: 'post', url: url, data: data, ...config}).then((response) => {
                resolve(response.data);
            }).catch((error) => {
                reject(error);
            });
        });
    },

    /**
     * DELETE 请求
     * @param url 接口地址
     * @param data 请求参数
     * @param config 请求配置
     * @returns {Promise<unknown>} 结果
     */
    delete: (url, data = {}, config = {}) => {
        return new Promise((resolve, reject) => {
            axios({method: 'delete', url: url, data: data, ...config}).then((response) => {
                resolve(response.data);
            }).catch((error) => {
                reject(error);
            });
        });
    },

    /**
     * PUT 请求
     * @param url 接口地址
     * @param data 请求参数
     * @param config 请求配置
     * @returns {Promise<unknown>} 结果
     */
    put: (url, data = {}, config = {}) => {
        return new Promise((resolve, reject) => {
            axios({method: 'put', url: url, data: data, ...config}).then((response) => {
                resolve(response.data);
            }).catch((error) => {
                reject(error);
            });
        });
    },

    /**
     * GET 请求
     * @param url 接口地址
     * @param params 请求参数
     * @param config 请求配置
     * @returns {Promise<unknown>} 结果
     */
    get: (url, params = {}, config = {}) => {
        return new Promise((resolve, reject) => {
            axios({method: 'get', url: url, params: params, ...config}).then((response) => {
                resolve(response.data);
            }).catch((error) => {
                reject(error);
            });
        });
    },

    /**
     * PATCH 请求
     * @param url 接口地址
     * @param data 请求参数
     * @param config 请求配置
     * @returns {Promise<unknown>} 结果
     */
    patch: (url, data = {}, config = {}) => {
        return new Promise((resolve, reject) => {
            axios({method: 'patch', url: url, data: data, ...config}).then((response) => {
                resolve(response.data);
            }).catch((error) => {
                reject(error);
            });
        });
    },

    /**
     * JSONP 请求
     * @param url 接口地址
     * @param name 请求名称
     * @returns {Promise<unknown>} 结果
     */
    jsonp: function (url, name = 'jsonp') {
        return new Promise((resolve) => {
            const script = document.createElement('script');
            script.id = `jsonp${Math.ceil(Math.random() * 1000000)}`
            script.type = 'text/javascript'
            script.src = url
            window[name] = (response) => {
                resolve(response)
                document.getElementsByTagName('head')[0].removeChild(script)
                try {
                    delete window[name];
                } catch (e) {
                    window[name] = undefined;
                }
            }
            document.getElementsByTagName('head')[0].appendChild(script)
        })
    },

    /**
     * 下载请求
     * @param url 接口地址
     * @param name 文件名
     * @returns {Promise<unknown>} 结果
     */
    download: (url, name) => {
        modal.openLoading("正在下载数据，请稍候...");
        axios({method: 'get', url: url, responseType: 'blob'}).then((response) => {
            const isBlob = blobValidate(response.data);
            if (isBlob) {
                const blob = new Blob([response.data], {type: 'application/zip'})
                saveTo(blob, name)
            } else {
                modal.errorMessage("文件下载异常");
            }
            modal.closeLoading();
        }).catch((error) => {
            console.error(error);
            modal.errorMessage("下载文件出现错误，请联系管理员！");
            modal.closeLoading();
        });
    },
};

export default request;
